package com.ys.http.download;

import android.util.Log;

import com.ys.http.api.DownLoadApi;
import com.ys.http.network.DownloadInterceptor;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.concurrent.TimeUnit;

import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.schedulers.Schedulers;
import okhttp3.OkHttpClient;
import okhttp3.ResponseBody;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava3.RxJava3CallAdapterFactory;

/***
 * 文件下载方法
 * 链式调用
 *new DownloadTask.Builder()
 * setDownloadUrl
 * setSaveUrl
 * setOnDownloadListener
 *  .build();
 *   mTask.start();
 *
 *   停止方法
 *   mTask.stop();
 *
 */
public class DownloadTask2 {

    private static final String TAG = "DownloadTask";
    private static final int DEFAULT_TIMEOUT = 15;
    private Retrofit retrofit;
    private OnDownloadListener listener;
    private String mDownloadUrl;
    private String mSaveUrl;

    private Disposable mDisposable;
    private final DownloadInterceptor mInterceptor;

    private DownloadTask2(String downloadUrl, String savePath, OnDownloadListener listener) {
        this.mDownloadUrl = downloadUrl;
        this.mSaveUrl = savePath;
        this.listener = listener == null ? new DefaultDownloadListener() : listener;
        mInterceptor = new DownloadInterceptor(listener);

        OkHttpClient httpClient = new OkHttpClient.Builder()
                .addInterceptor(mInterceptor)
                .retryOnConnectionFailure(true)
                .connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
                .build();

        try {
            retrofit = new Retrofit.Builder()
                    .baseUrl("http://www.download/")
                    .client(httpClient)
                    .addCallAdapterFactory(RxJava3CallAdapterFactory.create())
                    .build();
        } catch (Exception e) {
            e.printStackTrace();
            Log.e(TAG, e.getMessage());
        }
    }

    /**
     * 开始下载
     */
    public void start() {
        if (retrofit == null || mDownloadUrl == null || mSaveUrl == null) {
            Log.e(TAG, "error==========>");
            Log.e(TAG, "retrofit is null or mDownloadUrl is null or mSaveUrl is null");
            return;
        }
        stop();
        // subscribeOn()改变调用它之前代码的线程
        // observeOn()改变调用它之后代码的线程
        mDisposable = retrofit.create(DownLoadApi.class)
                .download(mDownloadUrl)
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .map(ResponseBody::byteStream)
                .observeOn(Schedulers.computation())
                .doOnNext(inputStream -> writeFile(inputStream, mSaveUrl))
                .map(inputStream -> mSaveUrl)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(savePath -> {
                    listener.onSuccess(savePath);
                }, throwable -> {
                    mInterceptor.dispose();
                    listener.onFailure(throwable);
                });
    }

    public void stop() {
        if (mDisposable != null) {
            mDisposable.dispose();
            mInterceptor.dispose();
            mDisposable = null;
        }
    }

    /**
     * 将输入流写入文件
     *
     * @param inputStream
     * @param filePath
     */
    private void writeFile(InputStream inputStream, String filePath) throws Exception {
        int index = filePath.lastIndexOf(File.separator);
        String pathDir = filePath.substring(0, index);
        File fileDir = new File(pathDir);
        if (!fileDir.isDirectory()) {
            fileDir.mkdirs();
        }
        File file = new File(filePath);
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(file);
            byte[] size = new byte[8192];
            int len = 0;
            while ( (len = inputStream.read(size)) != -1) {
                fos.write(size, 0, len);
            }

        } finally {
            inputStream.close();
            if (fos != null) {
                fos.close();
            }
        }
    }

    public static class Builder {
        private OnDownloadListener listener;
        private String downloadUrl;
        private String savePath;

        public Builder setSavePath(String path) {
            this.savePath = path;
            return this;
        }

        public Builder setDownloadUrl(String downloadUrl) {
            this.downloadUrl = downloadUrl;
            return this;
        }

        public Builder setOnDownloadListener(OnDownloadListener listener) {
            this.listener = listener;
            return this;
        }

        public DownloadTask2 build() {
            return new DownloadTask2(downloadUrl, savePath, listener);
        }
    }

}
